﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Google.GData.Client;
using Google.GData.Contacts;
using System.Windows.Forms;

namespace GoogleContactMerge
{
    internal class ContactMerge
    {
        const string _applicationName = "JeffBuda-GoogleContactMerge-0";
        const string _feedName = "m8";
        const string _uriUserIDPart = "<<userID>>";
        const string _uriProjectionPart = "<<projection>>";
        const string _uriBase = 
            "http://www.google.com/m8/feeds/contacts/"
            +_uriUserIDPart
            +"/"
            +_uriProjectionPart;

        Service _service;
        readonly string _uri;
        readonly string _emailAddress;
        readonly string _password;

        public ContactMerge(string emailAddress, string password)
        {
            this._emailAddress = emailAddress;
            this._password = password;

            this._service = new Google.GData.Contacts.ContactsService(_applicationName);
            this._uri = _uriBase.Replace(_uriUserIDPart, emailAddress);
            this._uri = this._uri.Replace(_uriProjectionPart, "full");
            //this._uri = _uriBase.Replace(_uriUserIDPart, "default").Replace(_uriProjectionPart, "full");
        }

        public Exception Login()
        {
            this._service.setUserCredentials(_emailAddress, _password);
            
            try
            {
                Google.GData.Contacts.ContactsFeed feed = new Google.GData.Contacts.ContactsFeed(this._emailAddress, new Service(_applicationName));
            }
            catch (InvalidCredentialsException ex)
            {
                return ex;
            }

            return null;
        }

        public IEnumerable<DetailModel> GetDetailModels()
        {
            ContactsQuery cq = new ContactsQuery(ContactsQuery.CreateContactsUri(_emailAddress, ContactsQuery.fullProjection));
            cq.NumberToRetrieve = 999;
            AtomFeed queryResult;
            //try
            //{
                queryResult = this._service.Query(cq);
            //}
            //catch (Google.GData.Client.GDataRequestException ex)
            //{
            //    //no internet connection perhaps?

            //}
            var list = new List<DetailModel>();
            foreach (ContactEntry entry in queryResult.Entries)
            {
                var model = new DetailModel(entry);


                list.Add(model);
            }
            return list;
        }

        public IEnumerable<KeyValuePair<DetailModel, Exception>> UploadChanges(IEnumerable<DetailModel> models)
        {
            //do the deletes first to prevent conflicts (Google uses email address as primary/unique key)
            List<DetailModel> modelsToUpload = new List<DetailModel>(models);
            List<DetailModel> modelsDeleted = new List<DetailModel>();

            List<KeyValuePair<DetailModel, Exception>> resultList = new List<KeyValuePair<DetailModel, Exception>>();
            foreach (var model in modelsToUpload)
            {
                if (model.Delete)
                {
                    try
                    {
                        model.ContactEntry.Delete();
                    }
                    catch (Exception ex)
                    {
                        resultList.Add(new KeyValuePair<DetailModel, Exception>(model, ex));
                    }
                    resultList.Add(new KeyValuePair<DetailModel, Exception>(model, null));

                    modelsDeleted.Add(model);
                }
            }

            //remove the Deleted contacts from our list of updates
            foreach(var deletedModel in modelsDeleted)
            {
                modelsToUpload.Remove(deletedModel);
            }

            //now upload the contacts that were not deleted
            foreach (var model in modelsToUpload)
            {
                model.WriteToContactEntry();
                try
                {
                    model.ContactEntry.Update();
                }
                catch (Exception ex)
                {
                    resultList.Add(new KeyValuePair<DetailModel, Exception>(model, ex));
                    continue;
                }
                resultList.Add(new KeyValuePair<DetailModel, Exception>(model, null));
            }
            return resultList;
        }
    }
}
